package cn.blnp.net.flowable.listen.task;

import cn.blnp.net.flowable.listen.task.listener.MyTaskListener1;
import cn.blnp.net.flowable.listen.task.listener.MyTaskListener2;
import cn.blnp.net.flowable.listen.task.listener.MyTaskListenerBean;
import cn.hutool.core.map.MapUtil;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.*;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

/**
 * <h3>监听器-任务监听器</h3>
 *
 * @author <a href="mailto:blnp.yibin@qq.com">lyb</a>
 * @version 1.0
 * @since 2025/5/21 13:36
 */
@Slf4j
@SpringBootTest
public class TaskListenFlowTest {

    @Resource
    private RepositoryService repositoryService;
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private TaskService taskService;
    @Resource
    private HistoryService historyService;
    @Resource
    private ManagementService managementService;

    /**
     *  <h1>任务监听器应用</h1>
     *  <hr/>
     *  <p>
     *   &emsp;&emsp;Flowable提供了任务监听器，用于在触发与某个任务相关的事件时执行自定义Java类或表达式。任务监听器只能在用户任务节点上配置。可被任务监听器捕获的任务相关事件类型包括以下4种。
     *   <ol>
     *       <li>
     *           <b>任务创建（create）事件：</b>发生在任务创建时，所有属性被设置后。
     *       </li>
     *       <li>
     *           <b>任务指派（assignment）事件：</b>发生在将任务指派给某人时。需要注意的是，该事件在任务创建事件前执行。
     *       </li>
     *       <li>
     *           <b>任务完成（complete）事件：</b>发生在任务完成时，即任务数据从执行数据表删除之前。
     *       </li>
     *       <li>
     *           <b>任务删除（delete）事件：</b>发生在任务被删除之前。当使用taskService的complete()方法完成任务时也会执行。
     *       </li>
     *   </ol>
     *   <pre>
     *       {@code
     *          <userTask id="myTask" name="用户任务1" >
     *              <extensionElements>
     *                  <flowable:taskListener event="create" class="com.bpm.example.tasklistener.demo.listener.MyTaskCreateListener" />
     *              </extensionElements>
     *          </userTask>
     *       }
     *   </pre>
     *  </p>
     *  <h2>1、通过class属性配置任务监听器</h2>
     *  <p>
     *   &emsp;&emsp;配置任务监听器可以通过class属性指定监听器的Java类，通常通过自定义类实现，即需要实现org.flowable.engine.delegate.TaskListener接口的notify()方法。为用户任务
     *   配置create事件的任务监听器的示例代码如下：
     *   <pre>
     *       {@code
     *          <userTask id="myTask" name="用户任务1" >
     *              <extensionElements>
     *                  <flowable:taskListener event="create" class="com.bpm.example.tasklistener.demo.listener.MyTaskListener1" >
     *                      <flowable:field name="fixedValue" stringValue="这是一个固定值." />
     *                      <flowable:field name="dynamicValue" expression="${myVar}" />
     *                  </flowable:taskListener>
     *              </extensionElements>
     *          </userTask>
     *       }
     *   </pre>
     *   > 监听对象实现：{@link MyTaskListener1}
     *  </p>
     *  <h2>2、通过expression属性配置任务监听器</h2>
     *  <p>
     *   &emsp;&emsp;配置任务监听器可以使用expression属性通过配置方法表达式实现，即使用UEL表达式指定监听器的JavaBean和执行方法。为用户任务配置assignment事件的任务监听器的示例代码如下：
     *   <pre>
     *       {@code
     *          <userTask id="myTask" name="用户任务1">
     *              <extensionElements>
     *                  <flowable:taskListener event="assignment" expression="${myTaskListenerBean.testMethod(task)}" />
     *              </extensionElements>
     *          </userTask>
     *       }
     *   </pre>
     *   > 详见对象：{@link MyTaskListenerBean}
     *  </p>
     *  <h2>3、通过delegateExpression属性配置任务监听器</h2>
     *  <p>
     *   &emsp;&emsp;配置任务监听器可以使用delegateExpression配合UEL通过配置委托表达式实现，即配置一个实现org.flowable.engine.delegate.TaskListener的类。为用户任务配置complete事件的
     *   任务监听器的示例代码如下：
     *   <pre>
     *       {@code
     *          <userTask id="myTask" name="用户任务1">
     *              <extensionElements>
     *                  <flowable:taskListener event="complete" delegateExpression="${myTaskListener2}"/>
     *              </extensionElements>
     *          </userTask>
     *       }
     *   </pre>
     *   > 监听实现：{@link MyTaskListener2}
     *  </p>
     *  <h2>4、通过配置脚本配置任务监听器</h2>
     *  <pre>
     *      <userTask id="myTask" name="用户任务1">
     *          <extensionElements>
     *              <flowable:taskListener event="delete" class="org.flowable.engine.impl.bpmn.listener.ScriptTaskListener">
     *                  <flowable:field name="script">
     *                      <flowable:string>
     *                          println("============通过脚本指定的监听器开始============");
     *                          def taskDefinitionKey = task.getTaskDefinitionKey();
     *                          def eventName = task.getEventName();
     *                          println("事件名称:" + ${eventName});
     *                          println("taskDefinitionKey:" + ${taskDefinitionKey});
     *                          println("============通过脚本指定的监听器结束============");
     *                          return taskDefinitionKey + eventName;
     *                      </flowable:string>
     *                  </flowable:field>
     *                  <flowable:field name="language" stringValue="groovy"/>
     *                  <flowable:field name="resultVariable" stringValue="myVar"/>
     *              </flowable:taskListener>
     *          </extensionElements>
     *      </userTask>
     *  </pre>
     *
     *  <h2>案例演示</h2>
     *  <p>
     *      <b>流程定义文件：</b>{@link flow/taskListenerProcess.bpmn20.xml}<br/>
     *      <b>流程预览图：</b><br/>
     *      <img src="https://cdn4.winhlb.com/2025/05/21/682d798e5290a.png" />
     *  </p>
     **/
    @Test
    public void test() {
        Deployment deploy = repositoryService.createDeployment()
                .name("任务监听器-演示案例")
                .addClasspathResource("flow/taskListenerProcess.bpmn20.xml")
                .deploy();
        log.info("部署流程定义：{}", deploy.getId());
        ProcessDefinition procDef = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deploy.getId())
                .singleResult();
        log.info("流程定义编号：{}", procDef.getId());
        //设置流程变量
        Map<String, Object> varMap1 = MapUtil.builder(new HashMap<String, Object>())
                .put("myVar", "张三")
                .build();
        //启动流程实例
        ProcessInstance procInst = runtimeService.startProcessInstanceById(procDef.getId(), varMap1);
        //查询任务
        Task task = taskService.createTaskQuery()
                .processInstanceId(procInst.getId()).singleResult();
        //设置任务办理人
        task.setAssignee("安琪拉");
        //办理任务
        taskService.complete(task.getId());

        /**
         *  演示结果：
         *  2025-05-21 15:08:58.189  INFO 62676 --- [           main] c.b.n.f.listen.task.TaskListenFlowTest   : 部署流程定义：76ab62c6-3612-11f0-b2b0-50ebf6ec8f6d
         * 2025-05-21 15:08:58.198  INFO 62676 --- [           main] c.b.n.f.listen.task.TaskListenFlowTest   : 流程定义编号：taskListenerProcess:4:76f4c7d8-3612-11f0-b2b0-50ebf6ec8f6d
         * 2025-05-21 15:08:58.319  INFO 62676 --- [           main] c.b.n.f.l.t.listener.MyTaskListenerBean  : （assignment）通过expression指定的监听器：用户任务userTask1的assignment事件触发
         * 2025-05-21 15:08:58.329  INFO 62676 --- [           main] c.b.n.f.l.task.listener.MyTaskListener1  : （create）通过class指定的监听器：用户任务userTask1的create事件触发
         * 2025-05-21 15:08:58.330  INFO 62676 --- [           main] c.b.n.f.l.task.listener.MyTaskListener1  : fixedValue属性值为：这是一个固定值.
         * 2025-05-21 15:08:58.330  INFO 62676 --- [           main] c.b.n.f.l.task.listener.MyTaskListener1  : dynamicValue属性值为：张三
         * 2025-05-21 15:08:58.417  INFO 62676 --- [           main] c.b.n.f.l.task.listener.MyTaskListener2  : （complete）通过delegateExpression指定的监听器：用户任务userTask1的complete事件触发
         * 通过脚本指定的监听器：用户任务userTask1的delete事件触发
         **/
    }
}
